//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   raster
//File Name     :   pixel_scan.v
//Module name   :   pixel scan
//Full name     :   pixel scan for overlap 2x2 block
//
//Author        :   zha daolu
//Email         :   
//Data          :   2020/6/1
//Version       :   V1.00
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//-----------------------------  
module pix_scan
(
    input					clk,               //input clock                          
    input					rst_n,             //input reset, low active              
    input					busy,              //input next stage busy                
    input             block_end,               //input block scan end                     
    input					fifo_empty,        //input 2x2 overlap block fifo empty                   
    input[5:0]				fifo_out,          //input 2x2 overlap block fifo data                 
    input signed[47:0]		a0,		           //input ee parameter                   
    input signed[47:0]		b0,		           //input ee parameter                   
    input signed[47:0]		a1,		           //input ee parameter                   
    input signed[47:0]		b1,		           //input ee parameter                   
    input signed[47:0]		a2,		           //input ee parameter
    input signed[47:0]		b2,		           //input ee parameter
    input signed[95:0]		ee0_int,           //input ee0 for tile left-bottom corner    
    input signed[95:0]		ee1_int,           //input ee1 for tile left-bottom corner    
    input signed[95:0]		ee2_int,           //input ee2 for tile left-bottom corner    
    output [3:0]			x_out,             //output pixel coordinate                          
    output [3:0]			y_out,             //output pixel coordinate                          
    output signed [95:0] ee0,                  //output edge function value for edge 01
    output signed [95:0] ee1,                  //output edge function value for edge 12
    output signed [95:0] ee2,                  //output edge function value for edge 20
    output 					xy_out_en,         //output valid
    output 					fifo_rd,           //fifo read
    output					pix_end            //2x2 block scan done
);


localparam		IDLE = 3'd0;
localparam		STEP0 = 3'd1;
localparam		STEP1 = 3'd2;
localparam		STEP2 = 3'd3;
localparam		STEP3 = 3'd4;

reg[2:0]		cur_state;
reg[2:0]		next_state;

reg[5:0]		position;

reg[3:0]		x_cal_temp;
reg[3:0]		y_cal_temp;
reg				cal_en_temp;
reg[3:0]		x_cal;
reg[3:0]		y_cal;
reg				cal_en;

reg[3:0]		x_ff1;
reg[3:0]		x_ff2;
reg[3:0]		y_ff1;
reg[3:0]		y_ff2;

reg block_end_ff1;
reg block_end_ff2;
reg block_end_ff3;

wire			overlap;
wire			pix_overlap_busy;

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			x_ff1 <= 4'b0;
		    x_ff2 <= 4'b0;
		    y_ff1 <= 4'b0;
		    y_ff2 <= 4'b0;
		end
	else if(!busy)
		begin
			x_ff1 <= x_cal;
		    x_ff2 <= x_ff1;
		    y_ff1 <= y_cal;
		    y_ff2 <= y_ff1;				
		end
end

always@(posedge clk or negedge rst_n)
begin
	if(~rst_n)
		block_end_ff1 <= 1'b0;
	else if(pix_end)
		block_end_ff1 <= 1'b0;
	else if(block_end)
		block_end_ff1 <= 1'b1;
end

always@(posedge clk or negedge rst_n)
begin
	if(~rst_n)
		begin
			block_end_ff2 <= 1'b0;
			block_end_ff3 <= 1'b0;
		end
	else if(pix_end)
		begin
			block_end_ff2 <= 1'b0;
			block_end_ff3 <= 1'b0;
		end
	else
		begin
			block_end_ff2 <= block_end_ff1;
			block_end_ff3 <= block_end_ff2;
		end
end



//fsm
//STEP0-3 for pixel 0-3
//0:left-bottom pixel
//1:right-bottom pixel
//2:left-up pixel
//3:right-up pixel
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cur_state <= IDLE;
	else
		cur_state <= next_state;
end

always@(*)
begin
	case(cur_state)
		IDLE:	if(!busy &&!fifo_empty)
				begin
					next_state = STEP0;
				end
				else 
					next_state = IDLE;
		STEP0:	if(!busy)
					next_state = STEP1;
				else
					next_state = STEP0;
		STEP1:	if(!busy)
					next_state = STEP2;
				else
					next_state = STEP1;
		STEP2:	if(!busy)
					next_state = STEP3;
				else
					next_state = STEP2;
		STEP3:	if(!busy && !fifo_empty)
					next_state = STEP0;
				else if(!busy)
					next_state = IDLE;
				else 
					next_state = STEP3;
		default: next_state = IDLE;
	endcase
end

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		position <= 8'b0;
	else if(fifo_rd)
		position <= fifo_out;
end


//pixel left-bottom coordinate
always@(*)
begin
	case(cur_state)
		STEP0:	begin
				if(!busy)
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b0};
						y_cal_temp  = {position[5],position[3],position[1],1'b0};
						cal_en_temp = 1'b1;				
					end
				else 
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b0};
						y_cal_temp  = {position[5],position[3],position[1],1'b0};
						cal_en_temp = 1'b0;				
					end
				end
					
		STEP1:	begin
				if(!busy)
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b1};
						y_cal_temp  = {position[5],position[3],position[1],1'b0};
						cal_en_temp = 1'b1;				
					end
				else 
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b1};
						y_cal_temp  = {position[5],position[3],position[1],1'b0};
						cal_en_temp = 1'b0;				
					end
				end

		STEP2:	begin
				if(!busy)
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b0};
						y_cal_temp  = {position[5],position[3],position[1],1'b1};
						cal_en_temp = 1'b1;				
					end
				else 
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b0};
						y_cal_temp  = {position[5],position[3],position[1],1'b1};
						cal_en_temp = 1'b0;				
					end
				end
		
		STEP3:	begin
				if(!busy)
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b1};
						y_cal_temp  = {position[5],position[3],position[1],1'b1};
						cal_en_temp = 1'b1;				
					end
				else 
					begin
						x_cal_temp  = {position[4],position[2],position[0],1'b1};
						y_cal_temp  = {position[5],position[3],position[1],1'b1};
						cal_en_temp = 1'b0;				
					end
				end
				
	  default:	begin
						x_cal_temp = 4'b0;
						y_cal_temp = 4'b0;
						cal_en_temp = 1'b0;
				end
	endcase
end

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			x_cal 	<= 4'b0;
			y_cal 	<= 4'b0;
			cal_en 	<= 1'b0;		
		end
	else if(!busy)
		begin
			x_cal 	<= x_cal_temp;
			y_cal 	<= y_cal_temp;
		    cal_en 	<= cal_en_temp;
		end
end


//pixel overlap judgment
pix_overlap  uut_pix_overlap
(
    .clk(clk),
    .rst_n(rst_n),
    .busy(busy),
    .x_in(x_cal),
    .y_in(y_cal),
    .xy_en(cal_en),
    .a0(a0),
    .b0(b0),
    .a1(a1),
    .b1(b1),
    .a2(a2),
    .b2(b2),
    .ee0_int(ee0_int),
    .ee1_int(ee1_int),
    .ee2_int(ee2_int),
    .overlap(overlap),
    .ee0_final(ee0),
    .ee1_final(ee1),
    .ee2_final(ee2),
    .pix_overlap_busy(pix_overlap_busy)
);


assign	x_out = x_ff2;
assign	y_out = y_ff2;
assign  xy_out_en = overlap;
assign	fifo_rd = (next_state == STEP0) && !busy;
assign	pix_end = fifo_empty && (!pix_overlap_busy) && ~cal_en_temp && block_end_ff3 && (cur_state == IDLE && next_state == IDLE);

endmodule

